package com.itheima.aspect;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * @Description: MyAspect1 通知类型示例
 * @Author: HH
 * @Date: 2025/4/21 10:43
 **/
@Slf4j
// @Aspect // 声明当前类为切面类
@Component // 将当前类注入到spring容器中, 方便自动注入管理
public class MyAspect1 {
    /**
     * 通知类型执行顺序：
     *  1. 无异常
     *      around before -> before -> 方法 -> afterReturning -> after -> around after
     *  2. 发生异常
     *      around before -> before -> 方法/异常 -> afterThrowing -> after
     */
    // 切入点方法: 用于将切入点表达式抽取出来，提高代码复用性
    @Pointcut("execution(* com.itheima.service.*.*(..))")
    public void pointCut() {
        // 切入点方法体，不需要写任何代码
    }

    // 前置通知
    // @Before("execution(* com.itheima.service.*.*(..))")
    // 前置通知（引入切入点方法）
    @Before("pointCut()")
    public void before(JoinPoint joinPoint) {
        log.info("============before...");
    }

    // 环绕通知
    // @Around("execution(* com.itheima.service.*.*(..))")
    @Around("pointCut()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        log.info("============around before...");

        //调用目标对象的原始方法执行
        Object result = proceedingJoinPoint.proceed(); // 环绕通知中需要手动调用原始方法执行

        //原始方法如果执行时有异常，环绕通知中的后置代码不会在执行了

        log.info("============around after...");
        return result;
    }

    // 后置通知（无论是否发生异常，都会执行的后置通知）
    // @After("execution(* com.itheima.service.*.*(..))")
    @After("pointCut()")
    public void after(JoinPoint joinPoint) {
        log.info("============after...");
    }

    // 返回后通知（程序在正常执行的情况下，会执行的后置通知）
    // @AfterReturning("execution(* com.itheima.service.*.*(..))")
    @AfterReturning("pointCut()")
    public void afterReturning(JoinPoint joinPoint) {
        log.info("============afterReturning...");
    }

    // 异常后通知（程序在出现异常的情况下，执行的后置通知）
    // @AfterThrowing("execution(* com.itheima.service.*.*(..))")
    @AfterThrowing("pointCut()")
    public void afterThrowing(JoinPoint joinPoint) {
        log.info("============afterThrowing...");
    }
}
